/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
 */

package service

//独立的支付服务，不依赖其他服务

import (
	"context"
	"crypto/rsa"
	"encoding/json"
	"errors"
	"log"
	"prim-server/logger"
	"prim-server/util"
	"time"

	"github.com/spf13/cast"
	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/core/option"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
	"github.com/wechatpay-apiv3/wechatpay-go/utils"
)

var (
	message = make(map[string]*util.PaymentMessage)
)
var paymentConfig *util.PaymentConfig

// 商户相关信息
var (
	appID                      = GetPaymentConfig().AppID                      // 公众号ID
	mchID                      = GetPaymentConfig().MchID                      // 商户号
	mchCertificateSerialNumber = GetPaymentConfig().MchCertificateSerialNumber // 商户证书序列号
	mchAPIv3Key                = GetPaymentConfig().MchAPIv3Key                // 商户APIv3密钥
	privateKeyPath             = GetPaymentConfig().PrivateKeyPath             // 商户私钥

	mPrivateKey *rsa.PrivateKey
	//仅仅在未对接第三方支付测试时使用
	UseThirdParty bool = false
)

// 写入第三方通知
func WriteIntoMessage(fundRecordId string, paymentInfo *util.PaymentMessage) {
	message[fundRecordId] = paymentInfo
}

// 读取第三方通知
func ReadFromMessage(fundRecordId string) (*util.PaymentMessage, error) {
	if _, ok := message[fundRecordId]; !ok {
		err := errors.New("can't find fundRecordId" + fundRecordId)
		logger.Error(err.Error())
		return nil, err
	}
	webMsg := message[fundRecordId]
	return webMsg, nil
}

// 检查第三方通知是否已经支付完成
func IsPayCompletedReadFromMessage(fundRecordId string) (bool, error) {
	webMsg, err := ReadFromMessage(fundRecordId)
	if err != nil {
		logger.Error(err.Error())
		return false, nil
	}
	if util.IsPayCompleted(webMsg.RecordStatus) {
		return true, nil
	}
	return false, nil
}

// 读取商户第三方配置文件
func GetPaymentConfig() *util.PaymentConfig {
	if paymentConfig == nil {
		//此处为测试返回
		paymentConfig = new(util.PaymentConfig)
		paymentConfig.MchID = "1900000000"
		paymentConfig.AppID = "wx123456789"
		paymentConfig.MchCertificateSerialNumber = "wx123456789"
		paymentConfig.MchAPIv3Key = "wx123456789"
		paymentConfig.PrivateKeyPath = "/conf/key.pem"
		return paymentConfig
	}
	return paymentConfig
}

func GetPrivateKey() *rsa.PrivateKey {
	var err error
	if mPrivateKey == nil {
		mPrivateKey, err = utils.LoadPrivateKeyWithPath(privateKeyPath)
		if err != nil {
			logger.Error(err.Error())
			return nil
		}
	}
	return mPrivateKey
}

// ExampleCloseOrder 关闭订单
// 以下情况需要调用关单接口：
// 1. 商户订单支付失败需要生成新单号重新发起支付，要对原订单号调用关单，避免重复支付；
// 2. 系统下单后，用户支付超时，系统退出不再受理，避免用户继续，请调用关单接口。
// outTradeNo为平台内部订单号
func ExampleCloseOrder(outTradeNo string) error {
	if UseThirdParty {
		// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
		mchPrivateKey := GetPrivateKey()
		ctx := context.Background()
		// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
		opts := []core.ClientOption{
			option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
		}
		client, err := core.NewClient(ctx, opts...)
		if err != nil {
			logger.Error(err.Error())
		}
		svc := native.NativeApiService{Client: client}
		result, err := svc.CloseOrder(ctx,
			native.CloseOrderRequest{
				OutTradeNo: core.String(outTradeNo),
				Mchid:      core.String(mchID),
			},
		)
		if err != nil {
			// 处理错误
			logger.Error(err.Error())
			return err
		} else {
			// 处理返回结果
			logger.Info("status=%d", result.Response.StatusCode)
			return nil
		}
	}
	return nil
}

// ExamplePrepay 生成预支付二维码
// 商户Native支付统一下单接口，微信后台系统返回链接参数code_url，商户后台系统将code_url值生成二维码图片，用户使用微信客户端扫码后发起支付
// notify即为接受异步通知的系统接口，可以获取订单的支付通知
func ExamplePrepay(prePayInfo util.PrepayInfo) (string, error) {
	if UseThirdParty {
		if util.IsWechatPay(prePayInfo.PaymentMethod) {
			// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
			mchPrivateKey := GetPrivateKey()
			ctx := context.Background()
			// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
			opts := []core.ClientOption{
				option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
			}
			client, err := core.NewClient(ctx, opts...)
			if err != nil {
				logger.Error(err.Error())
			}
			svc := native.NativeApiService{Client: client}
			resp, result, err := svc.Prepay(ctx,
				native.PrepayRequest{
					Appid:         core.String(appID),
					Mchid:         core.String(mchID),
					Description:   core.String("数字藏品"),
					OutTradeNo:    core.String(prePayInfo.OutTradeNo),
					TimeExpire:    core.Time(prePayInfo.TimeExpire),
					Attach:        core.String(prePayInfo.Description),
					NotifyUrl:     core.String(prePayInfo.NotifyUrl),
					GoodsTag:      core.String("Tests"),
					LimitPay:      []string{"LimitPay_example"},
					SupportFapiao: core.Bool(false),
					Amount: &native.Amount{
						Currency: core.String(prePayInfo.Currency),
						Total:    core.Int64(cast.ToInt64(prePayInfo.Price * 100)),
					},
				},
			)
			if err != nil {
				// 处理错误
				logger.Error(err.Error())
				return "", err
			} else {
				// 处理返回结果
				logger.Info("status=%d resp=%s", result.Response.StatusCode, resp)
				return resp.String(), nil
			}
		}
	}
	codeUrl := "weixin://wxpay/bizpayurl/up?pr=NwY5Mz9&groupid=00"
	return codeUrl, nil
}

// ExampleQueryOrderById 微信支付订单号查询订单
// 商户可以通过查询订单接口主动查询订单状态
// transactionId由微信支付系统生成的订单号
func ExampleQueryOrderById(transactionId string) (*payments.Transaction, *core.APIResult, error) {
	if UseThirdParty {
		// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
		mchPrivateKey := GetPrivateKey()
		ctx := context.Background()
		// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
		opts := []core.ClientOption{
			option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
		}
		client, err := core.NewClient(ctx, opts...)
		if err != nil {
			logger.Error(err.Error())
		}
		svc := native.NativeApiService{Client: client}
		resp, result, err := svc.QueryOrderById(ctx,
			native.QueryOrderByIdRequest{
				TransactionId: core.String(transactionId),
				Mchid:         core.String(mchID),
			},
		)
		if err != nil {
			// 处理错误
			logger.Error(err.Error())
			return nil, nil, err
		} else {
			// 处理返回结果
			logger.Info("status=%v,resp=%v", result.Response.StatusCode, resp)
			return resp, result, nil
		}
	} else {
		return nil, nil, nil
	}
}

// ExampleQueryOrderByOutTradeNo 商户订单号查询订单
// 商户可以通过查询订单接口主动查询订单状态
// paymentMethod为支付方式
func ExampleQueryOrderByOutTradeNo(outTradeNo string, paymentMethod string) (*payments.Transaction, *core.APIResult, error) {
	if UseThirdParty {
		if util.IsWechatPay(paymentMethod) {
			// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
			mchPrivateKey := GetPrivateKey()
			ctx := context.Background()
			// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
			opts := []core.ClientOption{
				option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
			}
			client, err := core.NewClient(ctx, opts...)
			if err != nil {
				log.Printf("new wechat pay client err:%s", err)
			}
			svc := native.NativeApiService{Client: client}
			resp, result, err := svc.QueryOrderByOutTradeNo(ctx,
				native.QueryOrderByOutTradeNoRequest{
					OutTradeNo: core.String(outTradeNo),
					Mchid:      core.String(mchID),
				},
			)
			if err != nil {
				// 处理错误
				logger.Error(err.Error())
				return nil, nil, err
			} else {
				// 处理返回结果
				logger.Info("status=%v resp=%v", result.Response.StatusCode, resp)
				return resp, result, nil
			}
		}
	}
	payment := payments.Transaction{}
	var tmpId = cast.ToString(time.Now().Unix())
	payment.TransactionId = &tmpId
	var tmp = "SUCCESS"
	payment.TradeState = &tmp
	return &payment, nil, nil
}
func DecryptFromBody(req *util.OrderNotifyReq) (*payments.Transaction, map[string]interface{}, error) {
	decryptCiphertext, err := utils.DecryptAES256GCM(mchAPIv3Key, req.Resource.AssociatedData, req.Resource.Nonce, req.Resource.Ciphertext)
	if err != nil {
		logger.Error(err.Error())
		return nil, nil, err
	}
	transaction := new(payments.Transaction)
	if err = json.Unmarshal([]byte(decryptCiphertext), &transaction); err != nil {
		logger.Error(err.Error())
		return nil, nil, err
	}
	//余下信息的解析，视情况而定
	content := make(map[string]interface{})
	if err = json.Unmarshal([]byte(decryptCiphertext), &content); err != nil {
		logger.Error(err.Error())
		return nil, nil, err
	}
	return transaction, content, nil
}
